统一管理本地存储
背景介绍
在团队开发中, 使用本地存储,分散在各个模块, 容易造成使用过程中,存储数据混乱, 无法有效管理, 那么这篇文章将解决这个状况, 集中统一管理本地存储。 希望能给大家带来方便
相关资料
本地存储MDN原生api
github地址
原型链
阮一峰es6 class基础知识
代码
提供的api与原生api相同, 并增强了原生的能力, 使用起来更加灵活方便。其中有些方法,是被定义在了其他工具里, 如func.filterFields: 过滤字符串使用。还有其他类型检测,isUndefined, isArray 等 均在 feitools中找到源码。
项已经发布到 npm 中了, 可以使用 npm i -S feitools 安装
定义 Memory 类
// 定义 Memery
class Memory {
constructor( key, type ){
this.key = key;
this.type = type;
// 保存 实例对象
this._getIntance( type, key, this );
// 存储类型 映射
this.__proto__.map = {
session: window.sessionStorage,
local: window.localStorage
}
}
}
实例方法 setItem
/**
* 功能: 存储数据
* 参数: value<any>, replacer[]
*/
setItem( value, replacer ){
this.map[ this.type ].setItem( this.key, func.filterFields( value, replacer ) );
}
实例方法 getItem
/**
* 功能: 获取 存储的值
* 参数: 无
* 返回值: 存储的数据
*/
getItem(){
return this.hasKey() && JSON.parse( this.map[ this.type ].getItem( this.key ) )
}
实例方法 removeItem
/**
* 功能: 删除储存
*/
removeItem(){
this.map[ this.type ].removeItem( this.key )
}
实例方法 hasKey
/**
* 功能: 检测 存储 是否存在
* 参数: 无
* 返回值: boolean
*/
hasKey() {
return this.key in this.map[ this.type ];
}
私有方法 _getIntance
/**
* 功能:存储实例对象, 内部方法( 不建议调用 )
* type: 存储类型, key: 数据的键
*/
_getIntance( type, key, that ){
if( that.constructor !== Memory ){
throw 'not allowed, this is a internal method!'
}
// 静态方法初始化时,会自动执行, 增加判断处理
if( isUndefined( type ) ) return;
const { instances } = this.constructor;
const values = instances[ type ] || [];
if( values.length !== 0 && values.includes( key ) ){
throw `Memory need a only key, the ${key} is existed, please check code!`
}
this.constructor.instances = { // 保存实例
...instances,
[ type ]: [ ...values, key ]
}
}
静态属性 instances
// 用于 保存 Memory 实例
static instances = {}
静态方法 clear
/**
* 功能:清空指定 type 存储数据
* 参数:type,存储类型
*/
static clear( type="local"){
new this().map[ type ].clear();
}
静态方法 clearAll
/**
* 功能:清空所有存储数据( 包括 local 和 session )
*/
static clearAll(){
this.clear( 'local' );
this.clear( 'session' );
}
静态方法 removeItems
/**
* 功能:批量删除 存储数据, 自动遍历所有存储
* 参数:keys, Array<key> | String
*/
static removeItems( keys=[] ){
const storageTypes = Object.values( new this().map );
keys = !isArray( keys ) ? keys.split(/\W+/g) : keys;
keys.forEach( key =>
storageTypes.forEach( item => item.removeItem( key ) )
);
}
静态方法 keys
/**
* 功能:获取存储 与存储数据的 key 值
* 返回值:Object<{[type]:Array<Object>}>
*/
static keys(){
return Object.entries( new this().map ).reduce( ( prevTotal, [ key, value ]) =>
({
...prevTotal,
[ key ]: new Array( value.length ).fill( '' ).map(
( item, index ) => value.key( index )
)
}), {}
);
}
以下代码为历史版本, 为了记录演变过程 保留 历史版本,
localStoage为本地存储,是一种永久性存储,除非手动清除。sessionStorage是会话存储,当浏览器关闭后,存储数据会自动清除。两种存储方式几乎都有相同的方法和属性;
1.localStorage.length 和 sessionStorage.length : 返回本地存储列表长度;需要说明的是可以通过localStorage对象获取对应的存储数据,比如已经存储了一个键为name的数据,使用localStorage.name获取存储数据;下面的方法都是基于localStorage 对象 或 sessionStorage 对象;
2.getItem( keyName )方法:通过键获取存储的数据;
3.setItem( keyName,value )方法:存储数据,keyName为存储数据的键,value实际要存储的数据(可以把keyName理解成 给要存储的数据起的名字,便于管理);
4.removeItem( keyName )方法: 将指定键名的数据删除;
5.clear() 方法:清空所有的存储数据;
6.key() 方法: 获取键值,需要注意的是并不能返回指定布尔值需要作进一步处理,下面是针对两种不同的存储方式使用统一的函数方式实现,欢迎各位提出意见。
7.es6 版本 发布在github 也可以使用 npm i -S feitools
https://github.com/lizhanyi/t...
/* 功能:抛出异常 , 调试使用
@param msg , 异常信息
*/
throwError : function( msg ){ // 调试使用
throw new Error( msg );
}
/* 功能:设置和获取数据
@param key,存储的键
@param value,待存储的数据
@param boolean,区分对象sessionStorage和localStorage
*/
setItem : function( key, value/*, boolean*/ ){
var
args = arguments,
len = args.length,
storage;
len == 0 && this.throwError('Not enough arguments to Storage.getItem.');
if( args[len-1] == true ){// 是session
storage = window.sessionStorage;
len == 1 && this.throwError('Not enough arguments to Storage.getItem.');
len >= 3 && storage.setItem( args[0], args[1] );
if( len == 2 ) return storage.getItem( args[0] );
}else{// 是local
storage = window.localStorage;
len >= 2 && storage.setItem( args[0], args[1] );
if( len == 1 ) return storage.getItem( args[0] );
}
}
/* 功能:删除存储数据
@param key,待删除的数据的键
@param boolean,区分对象sessionStorage和localStorage
*/
removeItem : function( key, boolean){ // 删除指定 key 的存储数据
var storage;
boolean ?
storage = window.sessionStorage : storage = window.localStorage;
return storage.removeItem( key );
}
clearItem : function(/*boolean*/){// 清空所有存储
arguments[0] ? window.sessionStorage.clear() : window.localStorage.clear();
}
/* 功能:判断是否有某一键名的数据,若存储数据存在返回true,否则返回false
@param key,指定的键名
@param boolean,区分对象sessionStorage和localStorage
用这种方式判断是否存储了某个数据,应该会好于使用getItem()方法;
*/
getKey : function( keyName/*boolean*/){ // 获取数据存储的键
var
temp,
args = arguments;
len = args.length;
args[len-1] == true ? temp = window.sessionStorage : temp = window.localStorage;
for(var i = 0; i < temp.length; i++)
if( keyName == temp.key(i) )
return true;
return false;
}
上面的封装在使用的时候有点纠结,使用多次和时间长的时候自己也不知道是使用了seeeion还是使用了local,所谓实践是检验真理的唯一标准
优化一下代码,使用构造函数方式实现
/*
@param way,存储方式,指定是session或local存储
*/
function Storage( way ){
this.map = {
'session' : window.sessionStorage,
'local' : window.localStorage
},
this.getItem = function( key ){
return this.map[way].getItem( key );
},
this.setItem = function( key, value ){
this.map[way].setItem( key,value )
},
this.removeItem = function( key ){
this.map[way].removeItem( key );
},
this.clear = function(){
this.map[way].clear();
},
this.getKey = function( key ){
//var len = map.way.length;
return key in map[way];
}
};
var local = new Storage('local');// 创建一个本地存储的实例
local.setItem('key','data');// 存储数据
local.getItem('key'); // 获取本地存储数据
local.removeItem('key'); // 删除键名为key的存储数据
local.getKey('key'); // 判断是否存在某一键的数据
local.clear();// 清空本地存储(删除所有的本地存储的数据)
var session = new Storage('session');// 创建一个session存储的实例
session.setItem('key','data');// 存储数据
session.getItem('key'); // 获取session存储数据
session.removeItem('key'); // 删除键名为key的存储数据
session.getKey('key'); // 判断是否存在某一键的数据
session.clear();// 清空会话存储(删除所有的session存储的数据)
继续优化:(使用原型对象,共享属性和方法)
function Storage( way ){
this.way = way;
};
Storage.prototype.map = {
'session' : window.sessionStorage,
'local' : window.localStorage
};
Storage.prototype.setItem = function( key, value){
this.map[this.way].setItem( key, value )
};
Storage.prototype.getItem = function( key ){
return this.map[this.way].getItem( key );
};
Storage.prototype.removeItem = function( key ){
this.map[this.way].removeItem( key )
};
Storage.prototype.clear = function(){
this.map[this.way].clear();
};
Storage.prototype.getKey = function( key ){
return key in this.map[this.way];
};
var local = new Storage('local');// 创建一个本地存储的实例
local.setItem('key','data');// 存储数据
local.getItem('key'); // 获取本地存储数据
local.removeItem('key'); // 删除键名为key的存储数据
local.getKey('key'); // 判断是否存在某一键的数据
local.clear();// 清空本地存储(删除所有的本地存储的数据)
再次优化代码:(针对上面的写法再来一次简化)
function Storage( way ){
this.way = way;
};
Storage.prototype = {
map : {
'session' : window.sessionStorage,
'local' : window.localStorage
},
setItem : function( key, value ){
this.map[this.way].setItem( key, value )
},
getItem : function( key ){
return this.map[this.way].getItem( key );
},
removeItem : function( key ){
this.map[this.way].removeItem( key );
},
clear : function(){
this.map[this.way].clear();
},
getKey : function( key ){
return key in this.map[this.way];
}
};
Storage.prototype.constructor = Storage;
这样看起来舒服多了,全部共享出去了,所有的实例都可以使用了,哈哈哈,亲测可用,如遇到问题可以随时交流,发现bug,也要及时反馈哈
关于prototype的几点说明
只要函数被声明了,就会产生对应的原型对象,即所有的函数都有原型对象,可以通过functionName.prototype访问原型对象。既然functionName.prototype是对象那么就可以通过'.'的方式设置属性和方法如:
function People(){};
People.prototype.name = '阿里巴巴';
People.prototype.get = function(){
console.log(this.name);
};
var people = new People(); // 实例化
console.log( people.name ); // 阿里巴巴
console.log( people.get() );// 阿里巴巴
console.log( people.constructor ); // People函数
console.log( people.__proto__.constructor ); // People函数
自定义方法优化
function Memory( key, way ){
this.way = way;
this.key = key;
};
Memory.prototype = {
constructor : Memory,
map : {
'session' : window.sessionStorage,
'local' : window.localStorage
},
setItem : function( value ){
this.map[this.way].setItem( this.key, JSON.stringify( value ) )
},
getItem : function(){
return JSON.parse( this.map[this.way].getItem( this.key ) );
},
removeItem : function(){
this.map[this.way].removeItem( this.key );
},
clear : function(){
this.map[this.way].clear();
},
getKey : function(){
return this.key in this.map[this.way];
}
};
var myStore = new Memory('key','session'); // 实例化一个对象,指定键值和存储方式
myStore.setItem('value'); // 指定存储的数据,可以是字符串、数字、json对象、数组。无需转换数据类型
myStore.getItem(); // 获取存储的数据,无需指定键值。
myStore.removeItem(); // 移除数据
var session = new Memory('clear','session');
session.clear(); // 清空所有的 session 存储
var local = new Memory('clear','local');
local.clear(); // 清空所有的 local 存储
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。